package com.taysear.parcel;

import java.math.BigDecimal;
import java.util.Date;
import java.util.UUID;

import javax.persistence.EntityManager;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.subject.Subject;

import com.taysear.parcel.domain.Account;
import com.taysear.parcel.domain.AccountDetail;
import com.taysear.parcel.domain.Parcel;
import com.taysear.parcel.domain.ParcelAction;
import com.taysear.parcel.domain.ParcelDetail;
import com.taysear.parcel.domain.ParcelHistory;
import com.taysear.parcel.domain.ParcelStatus;
import com.taysear.parcel.domain.ParcelType;
import com.taysear.parcel.domain.PaymentMode;
import com.taysear.parcel.domain.Station;
import com.taysear.parcel.domain.Substation;
import com.taysear.parcel.domain.User;
import com.taysear.parcel.domain.helpers.TParcel;
import com.taysear.parcel.fieldfactory.ParcelFieldFactory;
import com.taysear.parcel.util.Constants;
import com.taysear.parcel.util.Util;
import com.vaadin.addon.jpacontainer.JPAContainer;
import com.vaadin.addon.jpacontainer.JPAContainerFactory;
import com.vaadin.data.util.BeanItem;
import com.vaadin.data.util.filter.Not;
import com.vaadin.data.util.filter.Compare.Equal;
import com.vaadin.ui.Button;
import com.vaadin.ui.Field;
import com.vaadin.ui.Form;
import com.vaadin.ui.GridLayout;
import com.vaadin.ui.HorizontalLayout;
import com.vaadin.ui.Label;
import com.vaadin.ui.Panel;
import com.vaadin.ui.Table;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Window;
import com.vaadin.ui.Window.Notification;
import com.vaadin.ui.themes.Reindeer;
import com.vaadin.ui.themes.Runo;

public class ParcelForm extends Form{
	ParcelApplication app;
	Button save;
	Button createAnother;
	Button print;
	TParcel tp; 
	ParcelWindow parcelWindow;
	ParcelFieldFactory fieldFactory;
	private GridLayout ourLayout;
	private int type;
	private int typeCreate = 1;
	private int typeVieuw = 2;
	private int typeEdit = 3;
	private int typeCollect = 4;
	private int typeCancel = 5;
	private Subject currentUser;
	
	public ParcelForm(final ParcelApplication app, final ParcelWindow parcelWindow, String caption, int type) {
		super();
		this.app = app;
		this.parcelWindow = parcelWindow;
		this.type = type;
		this.currentUser = SecurityUtils.getSubject();
		
        ourLayout = new GridLayout(4, 11);

        // Use top-left margin and spacing
        ourLayout.setMargin(true, false, false, true);
        ourLayout.setSpacing(true);

        setLayout(ourLayout);
		setCaption(caption);
		setWriteThrough(false); // we want explicit 'apply'
		setInvalidCommitted(false); // no invalid values in datamodel

		// FieldFactory for customizing the fields and adding validators
		fieldFactory = new ParcelFieldFactory(app);
		setFormFieldFactory(fieldFactory);
		
		save = new Button("Save");
		save.setDisableOnClick(true);
		save.setStyleName(Reindeer.BUTTON_SMALL);
		save.addListener(new Button.ClickListener() {
			public void buttonClick(ClickEvent event) {
				if(isValid()){
					commit();
				}else {
					app.showNotification("Invalid Input: Please ensure all required fields contain valid data before saving.");
	               	save.setEnabled(true);
               	}
			}
		});
		
		createAnother = new Button("Create Another");
		createAnother.setStyleName(Reindeer.BUTTON_SMALL);
		createAnother.addListener(new Button.ClickListener() {
			public void buttonClick(ClickEvent event) {
				discard();
				setReadOnly(false);
				save.setEnabled(true);
				createAnother.setEnabled(false);
				print.setEnabled(false);
			}
		});
		createAnother.setVisible(false);
		
		print = new Button("Print");
		if (!currentUser.isPermitted(PermissionsConstants.PERMISSION_PARCEL_PRINT))
			print.setVisible(false);
		print.setDisableOnClick(true);
		print.setStyleName(Reindeer.BUTTON_SMALL);
		print.addListener(new Button.ClickListener() {
            @Override
            public void buttonClick(ClickEvent event) {
            	Parcel parcel = app.em.find(Parcel.class, tp.getId());
            	app.em.refresh(parcel);
            	getApplication().getMainWindow().addWindow(new PrintToPDF(app, parcel));
            	event.getButton().setEnabled(true);
            }
        });
		
		Button history = new Button("History");
		history.setStyleName(Reindeer.BUTTON_SMALL);
		history.setVisible(false);
		history.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
            	
            	JPAContainer<ParcelHistory> container = JPAContainerFactory.make(ParcelHistory.class, app.PERSISTENCE_UNIT);
            	container.addContainerFilter(new Equal("parcel.parcelId", tp.getId()));
            	String [] columns = new String[] {"Date", "User", "Action", "Description"};
            	ParcelHistoryTable table = new ParcelHistoryTable(app, container, columns);
            	
            	Window editWindow = new Window("Parcel history");
    	    	editWindow.center();
    	    	editWindow.setModal(true);
    			VerticalLayout verticalLayout = (VerticalLayout) editWindow.getContent();
    			verticalLayout.setMargin(true);
    	        verticalLayout.setSpacing(true);
    			verticalLayout.setSizeUndefined();
    	    	verticalLayout.addComponent(table);
    	    	getApplication().getMainWindow().addWindow(editWindow);
            }
        });
		
		Button close = new Button("Close");
		close.setStyleName(Reindeer.BUTTON_SMALL);
		close.setVisible(false);
		close.addListener(new Button.ClickListener() {
            public void buttonClick(ClickEvent event) {
                Window editWindow = (Window) event.getButton().getParent().getParent().getParent().getParent().getParent();
            	(editWindow.getParent()).removeWindow(editWindow);
            }
        });
        
		if(type != typeCreate){
			history.setVisible(true);
			close.setVisible(true);
		}
		if(type == typeCreate)
			print.setEnabled(false);
		
		createAnother.setEnabled(false);
		
		HorizontalLayout buttons = new HorizontalLayout();
		buttons.setSpacing(true);
		buttons.addComponent(save);
		buttons.addComponent(createAnother);
		buttons.addComponent(print);
		buttons.addComponent(history);
		buttons.addComponent(close);
		getFooter().addComponent(buttons);
		getFooter().setMargin(false, false, true, true);
	}
	
	public void initForm(){
		if(type == typeCreate){
			tp = new TParcel();
			tp = initCreate(tp);
		}
		
		BeanItem<TParcel> tParcelItem = new BeanItem<TParcel>(tp);
		setItemDataSource(tParcelItem); // bind to POJO via BeanItem
		
		JPAContainer<Station> senderStationContainer = JPAContainerFactory.make(Station.class, app.PERSISTENCE_UNIT);
		senderStationContainer.addContainerFilter(new Equal("stationId", tp.getStation()));
		fieldFactory.station.setContainerDataSource(senderStationContainer);
		fieldFactory.station.setValue(senderStationContainer.getItemIds().iterator().next());

		JPAContainer<Substation> senderSubstationsContainer = JPAContainerFactory.make(Substation.class, app.PERSISTENCE_UNIT);
		senderSubstationsContainer.addContainerFilter(new Equal("substationId", tp.getSubStation()));
		fieldFactory.subStation.setContainerDataSource(senderSubstationsContainer);
		fieldFactory.subStation.setValue(senderSubstationsContainer.getItemIds().iterator().next());
		if(tp.getDestination() != null){
			JPAContainer<Station> destinationStationsContainer = JPAContainerFactory.make(Station.class, app.PERSISTENCE_UNIT);
			destinationStationsContainer.addContainerFilter(new Equal("stationId", tp.getDestination()));
			fieldFactory.destination.setContainerDataSource(destinationStationsContainer);
			fieldFactory.destination.setValue(destinationStationsContainer.getItemIds().iterator().next());
		} else {
			JPAContainer<Station> destinationStationsContainer = JPAContainerFactory.make(Station.class, app.PERSISTENCE_UNIT);
			destinationStationsContainer.addContainerFilter(new Not(new Equal("stationId", tp.getStation())));
			fieldFactory.destination.setContainerDataSource(destinationStationsContainer);
		}
		if(tp.getDestinationSubstation() != null){
			JPAContainer<Substation> destinationSubstationsContainer = JPAContainerFactory.make(Substation.class, app.PERSISTENCE_UNIT);
			destinationSubstationsContainer.addContainerFilter(new Equal("substationId", tp.getDestinationSubstation()));
			fieldFactory.destinationSubstation.setContainerDataSource(destinationSubstationsContainer);
			fieldFactory.destinationSubstation.setValue(destinationSubstationsContainer.getItemIds().iterator().next());
		}
		if(tp.getAccount() != null){
			JPAContainer<Account> container = JPAContainerFactory.make(Account.class, app.PERSISTENCE_UNIT);
			container.addContainerFilter(new Equal("id", tp.getAccount()));
			fieldFactory.account.setContainerDataSource(container);
			fieldFactory.account.setValue(container.getItemIds().iterator().next());
		}
		
		if(type == typeVieuw){
			initEdit();
			initVieuw();
		}
		else if(type == typeEdit)
			initEdit();
		else if(type == typeCollect)
			initCollect();
	}
	
	private TParcel initCreate(TParcel tp){
		tp.setStation(app.getUser().getEmployee().getStation().getStationId());
		tp.setSubStation(app.getUser().getEmployee().getSubstation().getSubstationId());
		tp.setVatable(true);
		fieldFactory.verificationCodeLabel.setVisible(false);
		fieldFactory.verificationCode.setVisible(false);
		fieldFactory.account.setVisible(false);
		fieldFactory.accountLabel.setVisible(false);
		return tp;
	}
	
	private void initEdit(){
		fieldFactory.station.setReadOnly(true);
    	fieldFactory.subStation.setReadOnly(true);
    	fieldFactory.destination.setReadOnly(true);
    	fieldFactory.paymentMode.setReadOnly(true);
    	fieldFactory.parcelType.setReadOnly(true);
    	fieldFactory.quantity.setReadOnly(true);
    	fieldFactory.weight.setReadOnly(true);
    	fieldFactory.amount.setReadOnly(true);
    	fieldFactory.vatable.setEnabled(false);
    	fieldFactory.vatAmount.setReadOnly(true);
    	fieldFactory.senderIdentification.setReadOnly(true);
    	fieldFactory.receiverIdentification.setVisible(false);
    	fieldFactory.destinationSubstation.setReadOnly(true);
    	fieldFactory.verificationCode.setReadOnly(true);
    	fieldFactory.account.setReadOnly(true);
    	createAnother.setVisible(false);
	}
	
	private void initVieuw(){
		fieldFactory.senderName.setReadOnly(true);
		fieldFactory.senderTel.setReadOnly(true);
		fieldFactory.receiverName.setReadOnly(true);
		fieldFactory.receiverTel.setReadOnly(true);
		fieldFactory.description.setReadOnly(true);
	}
	
	private void initCollect(){
		fieldFactory.senderName.setReadOnly(true);
		fieldFactory.senderName.setRequired(false);
		fieldFactory.senderTel.setReadOnly(true);
		fieldFactory.senderTel.setRequired(false);
    	fieldFactory.destination.setReadOnly(true);
    	fieldFactory.destination.setRequired(false);
    	fieldFactory.destinationSubstation.setNullSelectionAllowed(false);
    	fieldFactory.destinationSubstation.setRequired(true);
    	fieldFactory.parcelType.setReadOnly(true);
    	fieldFactory.parcelType.setRequired(false);
    	fieldFactory.quantity.setReadOnly(true);
    	fieldFactory.quantity.setRequired(false);
    	fieldFactory.weight.setReadOnly(true);
    	fieldFactory.weight.setRequired(false);
    	
    	fieldFactory.station.setRequired(false);
    	fieldFactory.subStation.setRequired(false);
    	fieldFactory.paymentMode.setRequired(false);
    	fieldFactory.amount.setRequired(false);
    	fieldFactory.vatable.setRequired(false);
    	fieldFactory.vatAmount.setRequired(false);
		fieldFactory.verificationCode.setRequired(true);
    	
		createAnother.setVisible(false);
	}
	
	@Override
	public void commit() {
		EntityManager em = app.em;
		try{
			em.getTransaction().begin();
			if(type == typeCreate && tp.getId() == null){
				Parcel parcel = save(em);
				em.getTransaction().commit();
				super.commit();
				setReadOnly(true);
				tp.setId(parcel.getParcelId());
				
				Panel panel = new Panel("Parcel is successfully saved");
	        	panel.addStyleName(Runo.PANEL_LIGHT);
	        	String vOptions = "<ul> <li>Please provide the customer this pin: <h1>" +parcel.getVerificationCode() +"</h1></li>" +
	        					  	   "<li><b><i>Inform the customer that without this pin the parcel can't be collected.</i></b></li>" +
	        					  "</ul>";
	        	panel.addComponent(new Label(vOptions, Label.CONTENT_XHTML));
				
	        	final Window window = new Window();
	        	
	        	Button close = new Button("Close");
	        	close.addStyleName(Runo.BUTTON_SMALL);
	        	close.addListener(new Button.ClickListener() {
	    			public void buttonClick(ClickEvent event) {
	    				window.getParent().removeWindow(window);
	    			}
	        	});
	        	panel.addComponent(close);
	        	
		    	window.center();
		    	window.setModal(true);
				VerticalLayout verticalLayout = (VerticalLayout) window.getContent();
				verticalLayout.setMargin(true);
		        verticalLayout.setSpacing(true);
				verticalLayout.setSizeUndefined();
		    	verticalLayout.addComponent(panel);
		    	getApplication().getMainWindow().addWindow(window);
	        	
			}
			else if(type == typeEdit && tp.getId() != null){
				edit(em);
				em.getTransaction().commit();
				super.commit();
				save.setEnabled(true);
				app.showNotification(Constants.SUCCESSFULLY_SAVED_MESSAGE);
			}
			else if(type == typeCollect && tp.getId() != null){
				Parcel parcel = em.find(Parcel.class, tp.getId());
				if(verifyParcel(parcel)){
					collect(em, parcel);
					em.getTransaction().commit();
					super.commit();
					setReadOnly(true);
					app.showNotification("Parcel is set to collected.");
				} else {
					em.refresh(parcel);
					parcel.setVerificationAttempts(parcel.getVerificationAttempts()+1);
					if(parcel.getVerificationAttempts() == 3){
						setReadOnly(true);
						super.commit();
						parcel.setVerificationLock(true);
						ParcelStatus parcelStatus = em.find(ParcelStatus.class, Constants.PARCEL_STATUS_LOCKED);
						parcel.setParcelStatus(parcelStatus);
						ParcelAction parcelAction = em.find(ParcelAction.class, Constants.PARCEL_ACTION_LOCK);
						saveParcelHistory(em, parcel, app.getUser(), parcelAction, "Three times wrong verification code enterred");
						app.showNotification("Maximum attempts reached, parcel locked. Contact station manager !!..");
					} else if(parcel.getVerificationAttempts() <= 2){
						app.showNotification("Verification code is incorrect, please try again");
						save.setEnabled(true);
					}
					em.getTransaction().commit();
				}
			}
			createAnother.setEnabled(true);
			print.setEnabled(true);
			if(parcelWindow != null)
				parcelWindow.searchParcels();
		} catch (Exception e) {
			app.showNotification("Oooopss something whent wrong !!..");
			em.getTransaction().rollback();
			e.printStackTrace();
		}
	}
	
	@Override
	public boolean removeItemProperty(Object id) {
		return super.removeItemProperty(id);
	}; 
	
	/*
     * Override to get control over where fields are placed.
     */
    @Override
    protected void attachField(Object propertyId, Field field){
    	if(type == typeCollect)
    		attachFieldsForCollect(propertyId, field);
    	else
    		attachFields(propertyId, field);
    }
    
    private void attachFields(Object propertyId, Field field){
    	if ("station".equals(propertyId)) {
    		ourLayout.addComponent(fieldFactory.stationLabel, 0, 0);
    		field.setTabIndex(1);
    		ourLayout.addComponent(field, 1, 0);
		} else if ("subStation".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.subStationLabel, 0, 1);
			field.setTabIndex(2);
			ourLayout.addComponent(field, 1, 1);
		} else if ("senderName".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.senderNameLabel, 0, 2);
			field.setTabIndex(3);
			ourLayout.addComponent(field, 1, 2);
		} else if ("senderTel".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.senderTelLabel, 0, 3);
			field.setTabIndex(4);
			ourLayout.addComponent(field, 1, 3);
		} else if ("senderIdentification".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.senderIdentificationLabel, 0, 4);
			field.setTabIndex(5);
			ourLayout.addComponent(field, 1, 4);
		} else if ("destination".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.destinationLabel, 0, 5);
			field.setTabIndex(6);
			ourLayout.addComponent(field, 1, 5);
		}else if ("destinationSubstation".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.destinationSubstationLabel, 0, 6);
			field.setTabIndex(7);
			ourLayout.addComponent(field, 1, 6);
		} else if ("receiverName".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverNameLabel, 0, 7);
			field.setTabIndex(8);
			ourLayout.addComponent(field, 1, 7);
		} else if ("receiverTel".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverTelLabel, 0, 8);
			field.setTabIndex(9);
			ourLayout.addComponent(field, 1, 8);
		} else if ("receiverIdentification".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverIdentificationLabel, 0, 9);
			field.setTabIndex(10);
			ourLayout.addComponent(field, 1, 9);
		} else if ("verificationCode".equals(propertyId)) {
			if(currentUser.isPermitted(PermissionsConstants.PERMISSION_PARCEL_SHOW_VERIFICATIONCODE)){
				ourLayout.addComponent(fieldFactory.verificationCodeLabel, 0, 10);
				ourLayout.addComponent(field, 1, 10);
			}
		} else if ("paymentMode".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.paymentModeLabel, 2, 0);
			field.setTabIndex(11);
			ourLayout.addComponent(field, 3, 0);
		} else if ("account".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.accountLabel, 2, 1);
			field.setTabIndex(12);
			ourLayout.addComponent(field, 3, 1);
		} else if ("parcelType".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.parcelTypeLabel, 2, 2);
			field.setTabIndex(13);
			ourLayout.addComponent(field, 3, 2);
		} else if ("quantity".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.quantityLabel, 2, 3);
			field.setTabIndex(14);
			ourLayout.addComponent(field, 3, 3);
		} else if ("weight".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.weightLabel, 2, 4);
			field.setTabIndex(15);
			ourLayout.addComponent(field, 3, 4);
		} else if ("amount".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.amountLabel, 2, 5);
			field.setTabIndex(16);
			ourLayout.addComponent(field, 3, 5);
        } else if ("vatable".equals(propertyId)) {
        	ourLayout.addComponent(fieldFactory.vatableLabel, 2, 6);
        	field.setTabIndex(17);
			ourLayout.addComponent(field, 3, 6);
		} else if ("vatAmount".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.vatAmountLabel, 2, 7);
			field.setTabIndex(18);
			ourLayout.addComponent(field, 3, 7);
		} else if ("description".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.descriptionLabel, 2, 8);
			field.setTabIndex(19);
			ourLayout.addComponent(field, 3, 8, 3, 10);
		}
    }
	
    private void attachFieldsForCollect(Object propertyId, Field field){
    	if ("senderName".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.senderNameLabel, 0, 0);
			ourLayout.addComponent(field, 1, 0);
		} else if ("senderTel".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.senderTelLabel, 0, 1);
			ourLayout.addComponent(field, 1, 1);
		} else if ("destination".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.destinationLabel, 0, 2);
			ourLayout.addComponent(field, 1, 2);
		}else if ("destinationSubstation".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.destinationSubstationLabel, 0,3);
			field.setTabIndex(1);
			ourLayout.addComponent(field, 1, 3);
		} else if ("receiverName".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverNameLabel, 0, 4);
			field.setTabIndex(2);
			ourLayout.addComponent(field, 1, 4);
		} else if ("receiverTel".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverTelLabel, 0, 5);
			field.setTabIndex(3);
			ourLayout.addComponent(field, 1, 5);
		} else if ("receiverIdentification".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.receiverIdentificationLabel, 0, 6);
			field.setTabIndex(4);
			ourLayout.addComponent(field, 1, 6);
		} else if ("verificationCode".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.verificationCodeLabel, 0, 7);
			field.setTabIndex(5);
			ourLayout.addComponent(field, 1, 7);
		} else if ("parcelType".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.parcelTypeLabel, 2, 0);
			ourLayout.addComponent(field, 3, 0);
		} else if ("quantity".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.quantityLabel, 2, 1);
			ourLayout.addComponent(field, 3, 1);
		} else if ("weight".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.weightLabel, 2, 2);
			ourLayout.addComponent(field, 3, 2);
		} else if ("description".equals(propertyId)) {
			ourLayout.addComponent(fieldFactory.descriptionLabel, 2, 3);
			field.setTabIndex(6);
			ourLayout.addComponent(field, 3, 3, 3, 5);
		} 
    }
    
	private Parcel save(EntityManager em){
		Station senderStation = app.getUser().getEmployee().getStation();
		Substation senderSubstation = app.getUser().getEmployee().getSubstation();
		Station receiverStation = em.find(Station.class, getField("destination").getValue());
		Substation receiverSubstation = em.find(Substation.class, getField("destinationSubstation").getValue());
		PaymentMode payMode = em.find(PaymentMode.class, getField("paymentMode").getValue());
		ParcelType parcelType = em.find(ParcelType.class, getField("parcelType").getValue());
		ParcelStatus parcelStatus = em.find(ParcelStatus.class, Constants.PARCEL_STATUS_NEW); // new
		User user = app.getUser();
		ParcelAction parcelAction = em.find(ParcelAction.class, Constants.PARCEL_ACTION_CREAT); // Create
		
		int newWaybillNumber = senderSubstation.getWaybillNumber()+1;
		String waybillNumber = senderStation.getCode()+senderSubstation.getSubstationNumber()+"."+newWaybillNumber;
		
		ParcelDetail parcelDetail = saveParcelDetail(em, newWaybillNumber, senderStation, senderSubstation, receiverStation, receiverSubstation, payMode);
		Parcel parcel = saveParcel(em, parcelDetail, waybillNumber, senderStation, senderSubstation, payMode, parcelType, parcelStatus);
		if(payMode.getPaymentModeId() == Constants.PARCEL_PAYMENT_MODE_ACCOUNT){
			Account account = em.find(Account.class, getField("account").getValue());
			
			AccountDetail accountDetail = new AccountDetail();
			accountDetail.setAccount(account);
			accountDetail.setCredit(new BigDecimal(parcel.getAmount()));
			accountDetail.setDebit(new BigDecimal(0));
			accountDetail.setParcel(parcel);
			em.persist(accountDetail);
			em.flush();
			
			parcel.setAccount(account);
			em.merge(parcel);
		}
		saveParcelHistory(em, parcel, user, parcelAction, "Create");
		return parcel;
	}
	
	private void edit(EntityManager em) throws Exception{
		Parcel parcel = em.find(Parcel.class, tp.getId());
		em.refresh(parcel);
		if(parcel.getParcelStatus().getParcelStatusId() != Constants.PARCEL_STATUS_CANCELLED){ // is not cancelled
			ParcelStatus parcelStatus = em.find(ParcelStatus.class, Constants.PARCEL_STATUS_EDITED); // edited
			User user = app.getUser();
			ParcelAction parcelAction = em.find(ParcelAction.class, Constants.PARCEL_ACTION_EDIT); // Edit
			
			parcel = editParcel(em, parcel, parcelStatus);
			ParcelDetail parcelDetail = editParcelDetail(em, parcel);
			saveParcelHistory(em, parcel, user, parcelAction, "Edited");
		} else{
			app.showNotification("Parcel is cacelled, edit is not possible.");
			save.setEnabled(false);
			throw new Exception();
		}
	}
	
	private Boolean verifyParcel(Parcel parcel){
		return parcel.getVerificationCode().equalsIgnoreCase(getField("verificationCode").getValue().toString());
	}
	
	private void collect(EntityManager em, Parcel parcel) throws Exception{
		em.refresh(parcel);
		if(parcel.getParcelStatus().getParcelStatusId() != Constants.PARCEL_STATUS_CANCELLED){ // is not cancelled
			ParcelStatus parcelStatus = em.find(ParcelStatus.class, Constants.PARCEL_STATUS_COLLECTED); 
			User user = app.getUser();
			ParcelAction parcelAction = em.find(ParcelAction.class, Constants.PARCEL_ACTION_COLLECT); 
			
			parcel = editParcel(em, parcel, parcelStatus);
			ParcelDetail parcelDetail = editParcelDetail(em, parcel);
			String desc = getField("description").getValue() != null ? getField("description").getValue().toString(): "";
			saveParcelHistory(em, parcel, user, parcelAction, "Collected parcel, description: "+desc);
		} else{
			app.showNotification("Parcel is cacelled, edit is not possible.");
			throw new Exception();
		}
	}
	
	private Parcel saveParcel(EntityManager em, ParcelDetail parcelDetail, String waybillNumber, Station senderStation, Substation senderSubstation, PaymentMode payMode, ParcelType parcelType, ParcelStatus parcelStatus){
		Parcel parcel = new Parcel();
		Date date = new Date();
		parcel.setDate(date);
		parcel.setWaybillNumber(waybillNumber);
		parcel.setPaymentMode(payMode);
		parcel.setAmount(app.formatDouble(getField("amount").getValue().toString()));
		parcel.setVatAmount(app.formatDouble(getField("vatAmount").getValue().toString()));
		parcel.setQuantity(Integer.parseInt(getField("quantity").getValue().toString()));
		parcel.setWeight(Double.parseDouble(getField("weight").getValue().toString()));
		parcel.setParcelType(parcelType);
		parcel.setParcelStatus(parcelStatus);
		parcel.setParcelDetail(parcelDetail);
		parcel.setVatable((Boolean) getField("vatable").getValue());
		String desc = getField("description").getValue() != null ? getField("description").getValue().toString(): "";
		parcel.setDescription(desc);
		parcel.setUser(app.getUser());
		parcel.setVerificationCode(Util.generateKey(Constants.PARCEL_PIN_LENGTH));
		em.persist(parcel);
		return parcel;
	}
	
	private Parcel editParcel(EntityManager em, Parcel parcel, ParcelStatus parcelStatus){
		parcel.setParcelStatus(parcelStatus);
		if(type == typeCreate)
			parcel.setDescription(getField("description").getValue() != null ? getField("description").getValue().toString(): "");
		em.merge(parcel);
		return parcel;
	}
	
	private ParcelDetail saveParcelDetail(EntityManager em, Integer newWaybillNumber, Station senderStation, Substation senderSubstation, Station receiverStation, Substation receiverSubstation, PaymentMode payMode){
		senderSubstation.setWaybillNumber(newWaybillNumber);
		em.merge(senderSubstation);
		
		ParcelDetail parcelDetail = new ParcelDetail();
		parcelDetail = fillParcelDetail(parcelDetail);
		parcelDetail.setSenderStation(senderStation);
		parcelDetail.setSenderSubstation(senderSubstation);
		parcelDetail.setReceiverStation(receiverStation);
		parcelDetail.setReceiverSubstation(receiverSubstation);
		
		if(payMode.getPaymentModeId() == Constants.PARCEL_PAYMENT_MODE_ACCOUNT){
			Account account = em.find(Account.class, getField("account").getValue());
			parcelDetail.setSender(account.getCustomer());
		}
		
		em.persist(parcelDetail);
		return parcelDetail;
	}
	
	private ParcelDetail editParcelDetail(EntityManager em, Parcel parcel){
		ParcelDetail parcelDetail = parcel.getParcelDetail();
		parcelDetail = fillParcelDetail(parcelDetail);
		em.merge(parcelDetail);
		return parcelDetail;
	}
	
	private ParcelDetail fillParcelDetail(ParcelDetail parcelDetail){
		if(type == typeCreate | type == typeEdit){
			parcelDetail.setSenderName(getField("senderName").getValue().toString());
			parcelDetail.setSenderTel(getField("senderTel").getValue().toString());
			String senderIdentification = getField("senderIdentification").getValue() != null ? getField("senderIdentification").getValue().toString(): "";
			parcelDetail.setSenderIdentification(senderIdentification);
		} else if(type == typeCollect){
			Substation receiverSubstation = null;
			if(getField("destinationSubstation").getValue() != null)
				receiverSubstation = app.em.find(Substation.class, getField("destinationSubstation").getValue());
			parcelDetail.setReceiverSubstation(receiverSubstation);
			String receiverIdentification = getField("receiverIdentification").getValue() != null ? getField("receiverIdentification").getValue().toString(): "";
			parcelDetail.setReceiverIdentification(receiverIdentification);
		}
		parcelDetail.setReceiverName(getField("receiverName").getValue().toString());
		parcelDetail.setReceiverTel(getField("receiverTel").getValue().toString());
		
		return parcelDetail;
	}
	
	private void saveParcelHistory(EntityManager em, Parcel parcel, User user, ParcelAction parcelAction, String desc){ 
		ParcelHistory parcelHistory = new ParcelHistory();
		parcelHistory.setParcel(parcel);
		parcelHistory.setUser(user);
		Date date = new Date();
		parcelHistory.setDate(date);
		parcelHistory.setParcelAction(parcelAction);
		parcelHistory.setDescription(desc);
		em.persist(parcelHistory);
	}

}
